package jinyilw.tools.net.dev;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;

public final class NetworkObject extends NetworkPacket
{

	public static final Class<?> INTEGER_TYPE = Integer.TYPE,
			DOUBLE_TYPE = Double.TYPE, BOOLEAN_TYPE = Boolean.TYPE,
			FLOAT_TYPE = Float.TYPE, LONG_TYPE = Long.TYPE,
			SHORT_TYPE = Short.TYPE, BYTE_TYPE = Byte.TYPE,
			CHARACTER_TYPE = Character.TYPE;

	private Class<?> type;

	private int intValue;
	private double doubleValue;
	private boolean booleanValue;
	private float floatValue;
	private long longValue;
	private short shortValue;
	private byte byteValue;
	private char charValue;
	private String stringValue;

	public NetworkObject(short id)
	{
		this.setId(id);
		this.type = null;

		this.setCompressed(false);
	}

	public NetworkObject(short id, Class<?> type)
	{
		this.setId(id);
		this.type = type;

		this.setCompressed(type.equals(NetworkPacket.STRING_TYPE));
	}

	public NetworkObject(short id, int intValue)
	{
		this.setId(id);
		this.intValue = intValue;
		this.type = NetworkObject.INTEGER_TYPE;

		this.setCompressed(false);
	}

	public NetworkObject(short id, double doubleValue)
	{
		this.setId(id);
		this.doubleValue = doubleValue;
		this.type = NetworkObject.DOUBLE_TYPE;

		this.setCompressed(false);
	}

	public NetworkObject(short id, boolean booleanValue)
	{
		this.setId(id);
		this.booleanValue = booleanValue;
		this.type = NetworkObject.BOOLEAN_TYPE;

		this.setCompressed(false);
	}

	public NetworkObject(short id, float floatValue)
	{
		this.setId(id);
		this.floatValue = floatValue;
		this.type = NetworkObject.FLOAT_TYPE;

		this.setCompressed(false);
	}

	public NetworkObject(short id, long longValue)
	{
		this.setId(id);
		this.longValue = longValue;
		this.type = NetworkObject.LONG_TYPE;

		this.setCompressed(false);
	}

	public NetworkObject(short id, short shortValue)
	{
		this.setId(id);
		this.shortValue = shortValue;
		this.type = NetworkObject.SHORT_TYPE;

		this.setCompressed(false);
	}

	public NetworkObject(short id, byte byteValue)
	{
		this.setId(id);
		this.byteValue = byteValue;
		this.type = NetworkObject.BYTE_TYPE;

		this.setCompressed(false);
	}

	public NetworkObject(short id, char charValue)
	{
		this.setId(id);
		this.charValue = charValue;
		this.type = NetworkObject.INTEGER_TYPE;

		this.setCompressed(false);
	}

	public NetworkObject(short id, String stringValue)
	{
		this.setId(id);
		this.stringValue = stringValue;
		this.type = String.class;

		this.setCompressed(true);
	}

	public void read(DataInputStream input) throws IOException
	{
		if (this.type == null)
		{
			return;
		}
		if (this.type == NetworkObject.INTEGER_TYPE)
		{
			this.intValue = input.readInt();
		} else if (this.type == NetworkObject.DOUBLE_TYPE)
		{
			this.doubleValue = input.readDouble();
		} else if (this.type == NetworkObject.BOOLEAN_TYPE)
		{
			this.booleanValue = input.readBoolean();
		} else if (this.type == NetworkObject.FLOAT_TYPE)
		{
			this.floatValue = input.readFloat();
		} else if (this.type == NetworkObject.LONG_TYPE)
		{
			this.longValue = input.readLong();
		} else if (this.type == NetworkObject.SHORT_TYPE)
		{
			this.shortValue = input.readShort();
		} else if (this.type == NetworkObject.BYTE_TYPE)
		{
			this.byteValue = input.readByte();
		} else if (this.type == NetworkObject.CHARACTER_TYPE)
		{
			this.charValue = input.readChar();
		} else
		{
			this.stringValue = input.readUTF();
		}
	}

	public void write(DataOutputStream output) throws IOException
	{
		if (this.type == null)
		{
			return;
		}
		if (this.type == NetworkObject.INTEGER_TYPE)
		{
			output.writeInt(this.intValue);
		} else if (this.type == NetworkObject.DOUBLE_TYPE)
		{
			output.writeDouble(this.doubleValue);
		} else if (this.type == NetworkObject.BOOLEAN_TYPE)
		{
			output.writeBoolean(this.booleanValue);
		} else if (this.type == NetworkObject.FLOAT_TYPE)
		{
			output.writeFloat(this.floatValue);
		} else if (this.type == NetworkObject.LONG_TYPE)
		{
			output.writeLong(this.longValue);
		} else if (this.type == NetworkObject.SHORT_TYPE)
		{
			output.writeShort(this.shortValue);
		} else if (this.type == NetworkObject.BYTE_TYPE)
		{
			output.writeByte(this.byteValue);
		} else if (this.type == NetworkObject.CHARACTER_TYPE)
		{
			output.writeChar(this.charValue);
		} else
		{
			output.writeUTF(this.stringValue);
		}
	}

	public Class<?> getType()
	{
		return this.type;
	}

	public void setType(Class<?> type)
	{
		this.type = type;
	}

	public int getInt()
	{
		if (this.type != NetworkObject.INTEGER_TYPE)
		{
			throw new RuntimeException("Attempt to get integer from "
					+ this.type + " class");
		}
		return this.intValue;
	}

	public void setInt(int intValue)
	{
		if (this.type != NetworkObject.INTEGER_TYPE)
		{
			throw new RuntimeException("Attempt to set integer from "
					+ this.type + " class");
		}
		this.intValue = intValue;
	}

	public double getDouble()
	{
		if (this.type != NetworkObject.INTEGER_TYPE)
		{
			throw new RuntimeException("Attempt to get double from "
					+ this.type + " class");
		}
		return this.doubleValue;
	}

	public void setDouble(double doubleValue)
	{
		if (this.type != NetworkObject.DOUBLE_TYPE)
		{
			throw new RuntimeException("Attempt to set double from "
					+ this.type + " class");
		}
		this.doubleValue = doubleValue;
	}

	public boolean getBoolean()
	{
		if (this.type != NetworkObject.BOOLEAN_TYPE)
		{
			throw new RuntimeException("Attempt to get boolean from "
					+ this.type + " class");
		}
		return this.booleanValue;
	}

	public void setBoolean(boolean booleanValue)
	{
		if (this.type != NetworkObject.BOOLEAN_TYPE)
		{
			throw new RuntimeException("Attempt to set boolean from "
					+ this.type + " class");
		}
		this.booleanValue = booleanValue;
	}

	public float getFloat()
	{
		if (this.type != NetworkObject.FLOAT_TYPE)
		{
			throw new RuntimeException("Attempt to get float from " + this.type
					+ " class");
		}
		return this.floatValue;
	}

	public void setFloat(float floatValue)
	{
		if (this.type != NetworkObject.FLOAT_TYPE)
		{
			throw new RuntimeException("Attempt to set float from " + this.type
					+ " class");
		}
		this.floatValue = floatValue;
	}

	public long getLong()
	{
		if (this.type != NetworkObject.LONG_TYPE)
		{
			throw new RuntimeException("Attempt to get long from " + this.type
					+ " class");
		}
		return this.longValue;
	}

	public void setLong(long longValue)
	{
		if (this.type != NetworkObject.LONG_TYPE)
		{
			throw new RuntimeException("Attempt to set long from " + this.type
					+ " class");
		}
		this.longValue = longValue;
	}

	public short getShort()
	{
		if (this.type != NetworkObject.SHORT_TYPE)
		{
			throw new RuntimeException("Attempt to get short from " + this.type
					+ " class");
		}
		return this.shortValue;
	}

	public void setShort(short shortValue)
	{
		if (this.type != NetworkObject.SHORT_TYPE)
		{
			throw new RuntimeException("Attempt to set short from " + this.type
					+ " class");
		}
		this.shortValue = shortValue;
	}

	public byte getByte()
	{
		if (this.type != NetworkObject.BYTE_TYPE)
		{
			throw new RuntimeException("Attempt to get byte from " + this.type
					+ " class");
		}
		return this.byteValue;
	}

	public void setByte(byte byteValue)
	{
		if (this.type != NetworkObject.BYTE_TYPE)
		{
			throw new RuntimeException("Attempt to set byte from " + this.type
					+ " class");
		}
		this.byteValue = byteValue;
	}

	public char getChar()
	{
		if (this.type != NetworkObject.CHARACTER_TYPE)
		{
			throw new RuntimeException("Attempt to get char from " + this.type
					+ " class");
		}
		return this.charValue;
	}

	public void setChar(char charValue)
	{
		if (this.type != NetworkObject.CHARACTER_TYPE)
		{
			throw new RuntimeException("Attempt to set char from " + this.type
					+ " class");
		}
		this.charValue = charValue;
	}

	public String getString()
	{
		if (this.type == null || this.type.isPrimitive())
		{
			throw new RuntimeException("Attempt to get String from "
					+ this.type + " class");
		}
		return this.stringValue;
	}

	public void setString(String stringValue)
	{
		if (this.type == null || this.type.isPrimitive())
		{
			throw new RuntimeException("Attempt to set String from "
					+ this.type + " class");
		}
		this.stringValue = stringValue;
	}

	private static HashMap<Short, String> map;

	public NetworkPacket setDescription(String description)
	{
		if (NetworkConfig.DEBUG)
		{
			if (NetworkObject.map == null)
			{
				NetworkObject.map = new HashMap<>();
			}

			NetworkObject.map.put(this.getID(), description);
		}
		return this;
	}

	public String toString()
	{
		if (!NetworkConfig.DEBUG)
		{
			return super.toString();
		}

		StringBuilder buff = new StringBuilder();

		buff.append("NetworkObject ");
		if (NetworkObject.map != null)
		{
			String description = NetworkObject.map.get(this
					.getID());
			if (description != null)
			{
				buff.append(description).append(" ");
			}
		}
		if (this.isSendSender())
		{
			buff.append("Sender ID ").append(this.getSender()).append(" ");
		}
		buff.append("ID ").append(this.getID());
		if (this.isSendCode())
		{
			buff.append(" (code=").append(this.getCode()).append(")");
		}
		buff.append(": ");

		if (this.type == null)
		{
			buff.append("send ID only");
		} else if (this.type == NetworkObject.INTEGER_TYPE)
		{
			buff.append("int = ").append(this.intValue);
		} else if (this.type == NetworkObject.DOUBLE_TYPE)
		{
			buff.append("double = ").append(this.doubleValue);
		} else if (this.type == NetworkObject.BOOLEAN_TYPE)
		{
			buff.append("boolean = ").append(this.booleanValue);
		} else if (this.type == NetworkObject.FLOAT_TYPE)
		{
			buff.append("float = ").append(this.floatValue);
		} else if (this.type == NetworkObject.LONG_TYPE)
		{
			buff.append("long = ").append(this.longValue);
		} else if (this.type == NetworkObject.SHORT_TYPE)
		{
			buff.append("short = ").append(this.shortValue);
		} else if (this.type == NetworkObject.BYTE_TYPE)
		{
			buff.append("byte = ").append(this.byteValue);
		} else if (this.type == NetworkObject.CHARACTER_TYPE)
		{
			buff.append("char = ").append(this.charValue);
		} else
		{
			buff.append("String = ").append(this.stringValue);
		}
		return buff.toString();
	}

}
